package com.work.cos.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by test on 15-7-24.
 */
public class HttpClientUtil
{

    private static final Logger  logger         = LoggerFactory.getLogger(HttpClientUtil.class);
    private static       int     SocketTimeout  = 30000;//30秒
    private static       int     ConnectTimeout = 30000;//30秒
    private static       Boolean SetTimeOut     = true;
    private static       CookieStore cookieStore = null;

    public static CloseableHttpClient getHttpClient()
    {
        RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create();
        ConnectionSocketFactory plainSF = new PlainConnectionSocketFactory();
        registryBuilder.register("http", plainSF);
        //指定信任密钥存储对象和连接套接字工厂
        try
        {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            //信任任何链接
            SSLContext sslContext = SSLContexts.custom()
                    .loadTrustMaterial(trustStore, (x509Certificates, s) -> true).build();
            LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext,
                    NoopHostnameVerifier.INSTANCE);
            registryBuilder.register("https", sslSF);
        }
        catch (KeyStoreException e)
        {
            throw new RuntimeException(e);
        }
        catch (KeyManagementException e)
        {
            throw new RuntimeException(e);
        }
        catch (NoSuchAlgorithmException e)
        {
            throw new RuntimeException(e);
        }
        Registry<ConnectionSocketFactory> registry = registryBuilder.build();
        //设置连接管理器
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
        //构建客户端
        return HttpClientBuilder.create().setConnectionManager(connManager).build();
    }

    /**
     * get
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @return
     * @throws IOException
     */
    public static String[] get(String url, Map<String, String> queries) throws IOException
    {
        String[] responseBody = { "400", "" };

        //支持https
        CloseableHttpClient httpClient = getHttpClient();

        StringBuilder sb = new StringBuilder(url);

        if (queries != null && queries.keySet().size() > 0)
        {
            boolean firstFlag = true;
            Iterator iterator = queries.entrySet().iterator();
            while (iterator.hasNext())
            {
                Map.Entry entry = (Map.Entry<String, String>) iterator.next();
                if (firstFlag)
                {
                    sb.append("?" + (String) entry.getKey() + "=" + (String) entry.getValue());
                    firstFlag = false;
                }
                else
                {
                    sb.append("&" + (String) entry.getKey() + "=" + (String) entry.getValue());
                }
            }
        }

        HttpGet httpGet = new HttpGet(sb.toString());
        if (SetTimeOut)
        {
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SocketTimeout)
                    .setConnectTimeout(ConnectTimeout).build();//设置请求和传输超时时间
            httpGet.setConfig(requestConfig);
        }
        try
        {
            logger.debug("Executing request={} ", httpGet.getRequestLine());
            //请求数据
            CloseableHttpResponse response = httpClient.execute(httpGet);
            int status = response.getStatusLine().getStatusCode();
            logger.debug("status = {}", status);
            responseBody[0] = status + "";
            if (status == HttpStatus.SC_OK)
            {
                HttpEntity entity = response.getEntity();
                responseBody[1] = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            }
        }
        catch (Exception ex)
        {
            logger.error("Executing error={}", ex);
        }
        finally
        {
            httpClient.close();
        }
        return responseBody;
    }

    /**
     * post
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @param params  post form 提交的参数
     * @return
     * @throws IOException
     */
    public static String[] post(String url, Map<String, String> queries, Map<String, String> params) throws IOException
    {
        String[] responseBody = { "400", "" };
        //支持https
        CloseableHttpClient httpClient = getHttpClient();

        StringBuilder sb = new StringBuilder(url);

        if (queries != null && queries.keySet().size() > 0)
        {
            boolean firstFlag = true;
            Iterator iterator = queries.entrySet().iterator();
            while (iterator.hasNext())
            {
                Map.Entry entry = (Map.Entry<String, String>) iterator.next();
                if (firstFlag)
                {
                    sb.append("?" + (String) entry.getKey() + "=" + (String) entry.getValue());
                    firstFlag = false;
                }
                else
                {
                    sb.append("&" + (String) entry.getKey() + "=" + (String) entry.getValue());
                }
            }
        }

        //指定url,和http方式
        logger.debug("httpclient post url={}", sb.toString());
        HttpPost httpPost = new HttpPost(sb.toString());

        if (SetTimeOut)
        {
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SocketTimeout)
                    .setConnectTimeout(ConnectTimeout).build();//设置请求和传输超时时间
            httpPost.setConfig(requestConfig);
        }
        //添加参数
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        if (params != null && params.keySet().size() > 0)
        {
            Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
            while (iterator.hasNext())
            {
                Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
                nvps.add(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue()));
                logger.debug("key={}, value={}", entry.getKey(), entry.getValue());
            }


        }
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
        //请求数据
        CloseableHttpResponse response = httpClient.execute(httpPost);
        logger.debug("Executing request={} ", httpPost.getRequestLine());
        logger.debug("Executing request Entity={} ", httpPost.getEntity());
        try
        {
            int status = response.getStatusLine().getStatusCode();
            logger.debug("status={}", status);
            responseBody[0] = status + "";
            if (status == HttpStatus.SC_OK)
            {
                HttpEntity entity = response.getEntity();
                responseBody[1] = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            }
        }
        catch (Exception ex)
        {
            logger.error("Executing error={}", ex);
        }
        finally
        {
            response.close();
        }
        return responseBody;
    }
    
    /**
     * 
     * @param postUrl
     * @param params
     * @param cookieStore
     * @return
     * @throws IOException 
     * @throws  
     */
    public static String[] doPost(String postUrl,Map<String, String> params,String domain) throws IOException {
    	String[] responseBody = { "400", "" };
        // 创建HttpClientBuilder
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        // HttpClient
        CloseableHttpClient closeableHttpClient = null;
        if(cookieStore!=null){
            closeableHttpClient = httpClientBuilder.setDefaultCookieStore(cookieStore).build();
        }else{
            closeableHttpClient = httpClientBuilder.build();
        }
        HttpPost httpPost = new HttpPost(postUrl);
        if (SetTimeOut)
        {
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SocketTimeout)
                    .setConnectTimeout(ConnectTimeout).build();//设置请求和传输超时时间
            httpPost.setConfig(requestConfig);
        }
        httpPost.setEntity(new UrlEncodedFormEntity(getNameValuePairList(params), Consts.UTF_8));
        CloseableHttpResponse response = closeableHttpClient.execute(httpPost);
        try 
        {
            if(cookieStore == null){
            	setCookieStore(domain,response);
            }
            int status = response.getStatusLine().getStatusCode();
            logger.debug("status={}", status);
            responseBody[0] = status + "";
            if (status == HttpStatus.SC_OK)
            {
                HttpEntity entity = response.getEntity();
                responseBody[1] = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            }
        } 
        catch(Exception e) 
        {
        	logger.error("Executing error={}", e);
        }
        finally
        {
        	response.close();
        }
        return responseBody;
    }
    
    /**
     * 组装参数
     * @param params
     * @return
     */
    public static List<NameValuePair> getNameValuePairList(Map<String, String> params){
    	 //添加参数
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        if (params != null && params.keySet().size() > 0)
        {
            Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
            while (iterator.hasNext())
            {
                Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
                nvps.add(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue()));
                logger.debug("key={}, value={}", entry.getKey(), entry.getValue());
            }
        }
        return nvps;
    }
    
    /**
     * 将cookie保存到静态变量中供后续调用
     * @param httpResponse
     */
    public static void setCookieStore(String domain,HttpResponse httpResponse) {
    	logger.debug("----setCookieStore");
        cookieStore = new BasicCookieStore();
        // JSESSIONID
        String setCookie = httpResponse.getFirstHeader("Set-Cookie").getValue();
        String JSESSIONID = setCookie.substring("JSESSIONID=".length(),setCookie.indexOf(";"));
        logger.debug("JSESSIONID={}",JSESSIONID);
        // 新建一个Cookie
        BasicClientCookie cookie = new BasicClientCookie("JSESSIONID",JSESSIONID);
        cookie.setVersion(0);
        cookie.setDomain(domain);
        cookie.setPath("/");
        cookieStore.addCookie(cookie);
    }
    
    /**
     * 
     * @param url
     * @param params
     * @return
     * @throws IOException
     */
    public static String[] doPostJson(String url, String params) throws IOException {
    	String[] responseBody = { "400", "" };
        //支持https
        CloseableHttpClient httpClient = getHttpClient();

        //指定url,和http方式
        logger.debug("httpclient post url={}", url);
        HttpPost httpPost = new HttpPost(url);

        if (SetTimeOut)
        {
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SocketTimeout)
                    .setConnectTimeout(ConnectTimeout).build();//设置请求和传输超时时间
            httpPost.setConfig(requestConfig);
        }
       
        httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");
        StringEntity se = new StringEntity(params, Consts.UTF_8);
        se.setContentType("text/json");
        se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
        
        httpPost.setEntity(se);
        //请求数据
        CloseableHttpResponse response = httpClient.execute(httpPost);
        logger.debug("Executing request={} ", httpPost.getRequestLine());
        logger.debug("Executing request Entity={} ", httpPost.getEntity());
        try
        {
            int status = response.getStatusLine().getStatusCode();
            logger.debug("status={}", status);
            responseBody[0] = status + "";
            if (status == HttpStatus.SC_OK)
            {
                HttpEntity entity = response.getEntity();
                responseBody[1] = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            }
        }
        catch (Exception ex)
        {
            logger.error("Executing error={}", ex);
        }
        finally
        {
            response.close();
        }
        return responseBody;
    }
    
    /**
     * 
     * @param url
     * @param basicStr
     * @param params
     * @throws Exception
     */
    public static String[] doPostBasic(String url, String basicStr, String params) throws Exception {  
        
    	String[] responseBody = { "400", "" };
    	
    	CloseableHttpClient httpclient = HttpClients.createDefault();
        
        String encoding = Base64.getEncoder().encodeToString(basicStr.getBytes());
        
        try {
              	
        	HttpPost httpPost = new HttpPost(url);
        	
            // 向header中设置参数  
        	httpPost.addHeader("Authorization", "Basic " + encoding);
        	
        	StringEntity se = new StringEntity(params, Consts.UTF_8);
        	
        	se.setContentType("application/json;charset=utf-8");
        	
/*        	se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json;charset=utf-8"));*/
             
            httpPost.setEntity(se);
        	
            CloseableHttpResponse response = httpclient.execute(httpPost);
            
            System.out.println(response.getEntity());
            
            int status = response.getStatusLine().getStatusCode();  
            
            if (HttpStatus.SC_OK == status) { 
            	
            	responseBody[0] = status + "";
                if (status == HttpStatus.SC_OK)
                {
                    HttpEntity entity = response.getEntity();
                    responseBody[1] = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                } 
            }
        }catch(Exception ex){
        	
            logger.error("Executing error={}", ex);
        } finally {  
        	
            httpclient.close();  
        } 
        return responseBody;
    }  
}
